/**************************************************************************
** Qt Creator license header template
**   Special keywords: Programmer 2012/3/20 2012
**   Environment variables: 
**   To protect a percent sign, use '%'.
**************************************************************************/
#include <QFileDialog>



#include "glarea.h"
#include "dialogquadricparams.h"
#include "meshsimplificationquadric.h"
#include "progressivemeshquadric.h"
#include "infodialog.h"
#include "midpointprogressivemesh.h"

GLArea::GLArea(QWidget *parent) :
    QGLWidget(parent)
{
    //setFormat(QGLFormat(QGL::DoubleBuffer | QGL::DepthBuffer));
    currentModel = NULL;
    renderMode = MeshModel::SMOOTH;
}

void GLArea::cleanMesh(){
    if(currentModel == NULL){
        emit sendStatus(tr("No mesh in the scene, please load mesh first."));
        return;
    }
    QString info;
    currentModel->cleanMesh(info);
    InfoDialog id(info);
    id.exec();
}
void GLArea::showModelInfo(){

    if(currentModel == NULL){
        emit sendStatus(tr("No mesh in the scene, please load mesh first."));
        return;
    }
    QString info;
    currentModel->getMeshInfo(info);

    InfoDialog mid(info);
    mid.exec();

}
void GLArea::clear(){
    if(currentModel != NULL){
        currentModel->triMesh().Clear();
        delete currentModel;
        currentModel = NULL;
    }
    updateGL();
}
void GLArea::loadMesh()
{
    QString msg;
    QString pathName;

    pathName = QFileDialog::getOpenFileName(this,
                                            tr("Load a new Mesh"),
                                            QDir::currentPath(),
                                            tr("ply file (*.*)"));
    if(pathName.isEmpty()){
        msg = "load no mesh.";
        emit sendStatus(msg);
        return;
    }

    if(currentModel != NULL){
        delete currentModel;
        currentModel = NULL;
    }
    currentModel = new MeshModel;
    currentModel->loadMesh(pathName,msg);
    emit sendStatus(msg);
    updateGL();
}
void GLArea::createMidpointPM(){
    if(currentModel->triMesh().vn <= 0)
        return;
    bool isAccepted = false;
    int targetFaceNum = 100; //currentModel->triMesh().fn / 2;
    emit sendStatus(tr("setting the params for midpoint Progressive mesh."));
    MidParameters pp;
    ProgressiveMeshMid(currentModel->triMesh(),targetFaceNum,pp,this);
    updateGL();
//    if(qParamsDialog.exec() == QDialog::Accepted){

//        ProgressiveMesh(currentModel->triMesh(),targetFaceNum,false,pp,this);
//        updateGL();
//////////////////////////to be continued....
//        isAccepted = true;
//    }
    Sleep(10000);
//    if(isAccepted){
    emit sendStatus(tr("doing reconstruction"));
    RestoreProgressiveMeshMid(currentModel->triMesh(),pp,this);
    emit sendStatus(tr("reconstruction is done"));
    updateGL();
//    }
}
void GLArea::createProgressiveMesh(){
    //.............
    if(currentModel->triMesh().vn <= 0)
        return;
    bool isAccepted = false;
    int targetFaceNum = currentModel->triMesh().fn / 2;
    DialogQuadricParams qParamsDialog(targetFaceNum);////half number of current faces
    emit sendStatus(tr("setting the params for quadric Progressive mesh."));
    ProgressiveMeshQuadricParameters pp;
    if(qParamsDialog.exec() == QDialog::Accepted){
        qParamsDialog.getParams(pp,targetFaceNum);
        ProgressiveMesh(currentModel->triMesh(),targetFaceNum,false,pp,this);
        updateGL();
////////////////////////to be continued....
        isAccepted = true;
    }
    //Sleep(10000);
    if(isAccepted){
        emit sendStatus(tr("doing reconstruction"));
        RestoreProgressiveMesh(currentModel->triMesh(),pp,this);
        emit sendStatus(tr("reconstruction is done"));
    }

}
void GLArea::getQuadricParamsDialog()
{
    if(currentModel->triMesh().vn <= 0)
        return;

    int targetFaceNum = currentModel->triMesh().fn / 2;
    DialogQuadricParams qParamsDialog(targetFaceNum);////half number of current faces
    emit sendStatus(tr("setting the params for quadric simplification."));
    if(qParamsDialog.exec() == QDialog::Accepted){
        vcg::tri::TriEdgeCollapseQuadricParameter pp;
        qParamsDialog.getParams(pp,targetFaceNum);
        QuadricSimplification(currentModel->triMesh(),targetFaceNum,false,pp,this);
        updateGL();
    }

}

void GLArea::updateDrawArea(){
    updateGL();
}
void GLArea::changeRenderMode(int mode)
{
    renderMode = MeshModel::RenderMode(mode);

    QString msg = "render mode changed";
    emit sendStatus(msg);

    updateGL();
}

void GLArea::initializeGL()
{
    glClearColor(0,0,0,0);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_NORMALIZE);
    glEnable(GL_COLOR_MATERIAL);
    glEnable(GL_CULL_FACE);
    glEnable(GL_DEPTH_TEST);
}

void GLArea::resizeGL(int w, int h)
{
    glViewport(0,0,(GLsizei) w, (GLsizei) h);
    initializeGL();
}

void GLArea::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(40,GLArea::width()/(float)GLArea::height(),0.1,100);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(0,0,5, 0,0,0, 0,1,0);

    track.center = vcg::Point3f(0,0,0);
    track.radius = 1;
    track.GetView();
    track.Apply(false);

    glPushMatrix();

    if(currentModel != NULL)
        currentModel->render(renderMode);

    glPopMatrix();
    track.DrawPostApply();
}

void GLArea::mousePressEvent (QMouseEvent * e)
{
  e->accept ();
  setFocus ();
  track.MouseDown (e->x (), height () - e->y (), QT2VCG (e->button (), e->modifiers ()));
  updateGL ();
}

void GLArea::mouseMoveEvent (QMouseEvent * e)
{
  if (e->buttons ()) {
    track.MouseMove (e->x (), height () - e->y ());
    updateGL ();
  }
}

void GLArea::mouseReleaseEvent (QMouseEvent * e)
{
  track.MouseUp (e->x (), height () - e->y (), QT2VCG (e->button (), e->modifiers ()));
  updateGL ();
}

void GLArea::wheelEvent (QWheelEvent * e)
{
  const int WHEEL_STEP = 120;
  track.MouseWheel (e->delta () / float (WHEEL_STEP), QTWheel2VCG (e->modifiers ()));
  updateGL ();
}
